package com.jingdianjichi.auth.domain.service.impl;

import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.google.gson.Gson;
import com.jingdianjichi.auth.common.enums.AuthUserStatusEnum;
import com.jingdianjichi.auth.common.enums.IsDeleteFlagEnum;
import com.jingdianjichi.auth.domain.constants.AuthConstant;
import com.jingdianjichi.auth.domain.convert.AuthUserBOConvert;
import com.jingdianjichi.auth.domain.entity.AuthUserBO;
import com.jingdianjichi.auth.domain.redis.RedisUtil;
import com.jingdianjichi.auth.domain.service.AuthUseDomainService;
import com.jingdianjichi.auth.domain.util.PasswordTools;
import com.jingdianjichi.basic.entity.*;
import com.jingdianjichi.basic.service.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PostMapping;

import javax.annotation.Resource;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 用户领域层service的实现类
 */
@Service
@Slf4j
public class AuthUserDomainServiceImpl implements AuthUseDomainService {

	@Resource
	private AuthUserService authUserService; // 注入用户服务类

	@Resource
	private AuthRoleService authRoleService; // 注入角色服务类

	@Resource
	private AuthUserRoleService authUserRoleService; // 注入用户角色服务类

	@Resource
	private AuthPermissionService authPermissionService;

	@Resource
	private AuthRolePermissionService authRolePermissionService;

	@Resource
	private RedisUtil redisUtil;

	private String authPermissionPrefix = "auth.permission";

	private String authRolePrefix = "auth.role";

	// 验证码在Redis中的前缀
	private static final String LOGIN_PREFIX = "loginCode";

	/**
	 * 用户注册
	 * @param authUserBO 用户业务对象
	 * @return 注册是否成功
	 */
	@Override
	@Transactional(rollbackFor = Exception.class) // 声明事务，指定异常回滚
	public Boolean register(AuthUserBO authUserBO) {

		// 检查该用户是否存在数据库
		LambdaQueryWrapper<AuthUser> lambdaQueryWrapper = new LambdaQueryWrapper<>();
		lambdaQueryWrapper.eq(AuthUser::getUserName,authUserBO.getUserName());
		AuthUser user = authUserService.getOne(lambdaQueryWrapper);
		if(user != null) {
			// 注册失败
			return false;
		}
		// 将用户业务对象转换为用户实体类，用于数据库操作
		AuthUser authUser = AuthUserBOConvert.INSTANCE.convertBoToEntity(authUserBO);
		if(StringUtils.isNotBlank(authUser.getPassword())) {
			// 使用密码工具类对用户密码进行加密处理
			authUser.setPassword(PasswordTools.encrypt(authUserBO.getPassword()));
		}
		// 设置用户状态为开启（使用枚举类表示用户状态）
		authUser.setStatus(AuthUserStatusEnum.OPEN.getCode());
		// 设置用户为未删除状态（使用枚举类表示删除状态）
		authUser.setIsDeleted(IsDeleteFlagEnum.UN_DELETED.getCode());
		// 设置用户默认头像
		authUser.setAvatar("https://web-183.oss-cn-beijing.aliyuncs.com/typora/202402121828810.webp");
		// 保存用户信息到数据库，并返回保存结果
		boolean result = authUserService.save(authUser);

		// 查询角色信息，此处为查询普通管理员角色 （目的是查出角色表中，管理员这个角色的id）
		LambdaQueryWrapper<AuthRole> authRoleLambdaQueryWrapper = new LambdaQueryWrapper<>();
		authRoleLambdaQueryWrapper.eq(AuthRole::getRoleKey, AuthConstant.ADMIN_USER); // 根据角色关键字查询
		AuthRole authRole = authRoleService.getOne(authRoleLambdaQueryWrapper); // 获取角色信息

		// 创建 用户 角色 映射 表的实体
		AuthUserRole authUserRole = new AuthUserRole();
		authUserRole.setUserId(authUser.getId()); // 设置用户ID
		authUserRole.setRoleId(authRole.getId()); // 设置角色ID
		// 保存 一对用户角色的映射信息到数据库的用户角色映射表中
		authUserRoleService.save(authUserRole);

		// 将用户的角色信息缓存到Redis中 （使用 auth.role + 用户名 作为 key，该用户对应的角色信息作为value 缓存进redis ）
		String roleKey = redisUtil.buildKey(authRolePrefix, authUser.getUserName()); // 构建Redis键
		List<AuthRole> roleList = new LinkedList<>();
		roleList.add(authRole);
		redisUtil.set(roleKey, new Gson().toJson(roleList)); // 缓存角色信息

		// 查询该用户对应的角色的所有权限并缓存
		// 先根据角色id去映射表里面查询出该角色对应的所有权限id，再用权限id查询出对应的权限信息，最后缓存到redis里面
		LambdaQueryWrapper<AuthRolePermission> authRolePermissionLambdaQueryWrapper = new LambdaQueryWrapper<>();
		authRolePermissionLambdaQueryWrapper.eq(AuthRolePermission::getRoleId, authRole.getId());
		List<AuthRolePermission> rolePermissionList = authRolePermissionService.list(authRolePermissionLambdaQueryWrapper);
		List<Long> permissionIdList = rolePermissionList.stream().map(AuthRolePermission::getPermissionId).collect(Collectors.toList());
		// 根据权限ID列表查询权限信息
		List<AuthPermission> authPermissionList = authPermissionService.listByICondition(permissionIdList);
		// 缓存用户权限信息到Redis （auth.permission + 用户名 作为key，该用户的权限列表作为value 存入redis里面）
		String permissionKey = redisUtil.buildKey(authPermissionPrefix, authUser.getUserName());
		redisUtil.set(permissionKey, new Gson().toJson(authPermissionList));

		return result; // 返回注册操作的结果
	}

	/**
	 * 更新用户信息
	 * @param authUserBO 用户业务对象
	 * @return 更新是否成功
	 */
	@Override
	public Boolean update(AuthUserBO authUserBO) {
		AuthUser authUser = AuthUserBOConvert.INSTANCE.convertBoToEntity(authUserBO);
		LambdaQueryWrapper<AuthUser> lambdaQueryWrapper = new LambdaQueryWrapper<>();
		lambdaQueryWrapper.eq(AuthUser::getUserName, authUser.getUserName());
		// 根据ID更新用户信息
		boolean result = authUserService.update(authUser, lambdaQueryWrapper);
		return result;
	}

	/**
	 * 删除用户信息
	 * @param authUserBO 用户业务对象
	 * @return 删除是否成功
	 */
	@Override
	public Boolean delete(AuthUserBO authUserBO) {
		LambdaUpdateWrapper<AuthUser> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
		lambdaUpdateWrapper.eq(AuthUser::getId, authUserBO.getId())
				.set(AuthUser::getIsDeleted, IsDeleteFlagEnum.DELETED.getCode());
		// 逻辑删除用户信息
		boolean result = authUserService.update(null, lambdaUpdateWrapper);
		return result;
	}

	/**
	 * 用户启用/禁用
	 * @param authUserBO 用户业务对象
	 * @return 操作是否成功
	 */
	@Override
	public Boolean changeStatus(AuthUserBO authUserBO) {
		AuthUser authUser = AuthUserBOConvert.INSTANCE.convertBoToEntity(authUserBO);
		LambdaQueryWrapper<AuthUser> lambdaQueryWrapper = new LambdaQueryWrapper<>();
		lambdaQueryWrapper.eq(AuthUser::getId, authUser.getId());
		// 根据ID更改用户状态
		boolean result = authUserService.update(authUser, lambdaQueryWrapper);
		return result;
	}

	/**
	 * 个人信息查询
	 * @param authUserBO 用户业务对象
	 * @return 查询到的用户信息
	 */
	@Override
	public AuthUserBO getUserInfo(AuthUserBO authUserBO) {
		AuthUser authUser = AuthUserBOConvert.INSTANCE.convertBoToEntity(authUserBO);
		LambdaQueryWrapper<AuthUser> lambdaQueryWrapper = new LambdaQueryWrapper<>();
		lambdaQueryWrapper.eq(AuthUser::getUserName, authUser.getUserName());
		// 根据用户名查询用户信息
		AuthUser result = authUserService.getOne(lambdaQueryWrapper);
		// 将查询结果转换为业务对象返回
		AuthUserBO userBO = AuthUserBOConvert.INSTANCE.convertToBO(result);
		return userBO;
	}

	/**
	 * 登录方法实现
	 * @param validCode
	 * @return
	 */
	@Override
	public SaTokenInfo doLogin(String validCode) {
		// 根据用户提供的验证码构建登录的loginKey（loginCode + 验证码 构建key，value就是用户公众号的唯一id）
		String loginKey = redisUtil.buildKey(LOGIN_PREFIX, validCode);
		// 通过key获取对应的value（这里是用户的公众号的唯一标识），同时 openId 也用来对应用户表中的username（作为用户的用户名）
		String openId = redisUtil.get(loginKey);
		// 如果根据key没有获取到openId，说明验证码错误，直接返回
		if(StringUtils.isBlank(openId)) {
			return null;
		}
		// 查询用户是否存在数据库
		LambdaQueryWrapper<AuthUser> lambdaQueryWrapper = new LambdaQueryWrapper<>();
		lambdaQueryWrapper.eq(AuthUser::getUserName,openId);
		AuthUser authUser = authUserService.getOne(lambdaQueryWrapper);
		if(authUser == null) {
			// 用户在数据库不存在，需要注册一个新用户
			AuthUserBO authUserBO = new AuthUserBO();
			authUserBO.setUserName(openId);
			this.register(authUserBO);
		}else {
			// 如果用户存在，先将用户的角色id查出来
			LambdaQueryWrapper<AuthUserRole> authUserRoleLambdaQueryWrapper = new LambdaQueryWrapper<>();
			authUserRoleLambdaQueryWrapper.eq(AuthUserRole::getUserId, authUser.getId());
			AuthUserRole authRole = authUserRoleService.getOne(authUserRoleLambdaQueryWrapper);

			// 查询用户所有角色的权限并缓存（先根据角色id去映射表里面查询出所有角色对应的权限id，再用权限id查询出对应的权限信息，最后缓存到redis里面）
			LambdaQueryWrapper<AuthRolePermission> authRolePermissionLambdaQueryWrapper = new LambdaQueryWrapper<>();
			authRolePermissionLambdaQueryWrapper.eq(AuthRolePermission::getRoleId, authRole.getRoleId());
			List<AuthRolePermission> rolePermissionList = authRolePermissionService.list(authRolePermissionLambdaQueryWrapper);
			List<Long> permissionIdList = rolePermissionList.stream().map(AuthRolePermission::getPermissionId)
					.collect(Collectors.toList());
			// 根据权限ID列表查询权限信息
			List<AuthPermission> authPermissionList = authPermissionService.listByICondition(permissionIdList);
			// 缓存用户权限信息到Redis
			String userPermissionKey = redisUtil.buildKey(authPermissionPrefix, authUser.getUserName());
			redisUtil.set(userPermissionKey, new Gson().toJson(authPermissionList));
		}
		StpUtil.login(openId);
		// 获取 Token 直接返回
		SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
		return tokenInfo;
	}
}



